from flask import Flask, jsonify, request
import cv2
import math
import time
import numpy as np

app = Flask(__name__)

qrPoint = [(262, 237), (314, 242), (308, 293), (258, 289)]  # 二维码标准位置
qrLine = (242, 314, 293, 308)  # 二维码标准判断线

class DataManager:
    def __init__(self):
        # 初始化常量
        self.data = ""

    def update_constant(self, new_value):
        # 更新常量的值
        self.data = new_value

    def get_constant(self):
        # 获取常量的值
        return self.data
manager = DataManager()
class QrCode:

    # 计算偏转角度
    def calculate_angle_between_lines(self, line1, line2):
        # 确保线段都是 (x1, y1, x2, y2) 格式的
        x1, y1, x2, y2 = line1
        x3, y3, x4, y4 = line2

        # 计算第一条线的方向向量
        vector1 = (x2 - x1, y2 - y1)

        # 计算第二条线的方向向量
        vector2 = (x4 - x3, y4 - y3)

        # 计算两个向量之间的点积
        dot_product = vector1[0] * vector2[0] + vector1[1] * vector2[1]

        # 计算向量的长度
        length1 = math.sqrt(vector1[0] ** 2 + vector1[1] ** 2)
        length2 = math.sqrt(vector2[0] ** 2 + vector2[1] ** 2)

        # 计算夹角的余弦值
        cosine_similarity = dot_product / (length1 * length2)

        # 计算夹角的弧度
        angle_in_radians = math.acos(cosine_similarity)

        # 将弧度转换为度
        angle_in_degrees = math.degrees(angle_in_radians)

        return angle_in_degrees

    # 判读位置
    def compare_points(self, points1, points2):
        if len(points2) != 4:
            # 确保points2包含四个点
            return False

        for i in range(4):
            x1, y1 = points1[i]
            x2, y2 = points2[i]

            if abs(x1 - x2) > 50 or abs(y1 - y2) > 50:
                # 如果任何一个点的XY偏移大于50，返回False
                return False

        # 所有点的XY偏移都不大于50，返回True
        return True

    def QRCode_Detection(self, Color_choice):
        manager.update_constant("")  # 初始化质检状态
        array_data_list = []  # 保存二维码坐标
        angle_offset_str = "no "  # 用于保存二维码偏转角度，默认值为“no”
        is_position_correct = False  # 用于判断二维码位置是否正确，默认值为“false”
        res = "没有检测到二维码"  # 用于保存扫描二维码后获取到的内容
        successful_detection_count = 0  # 用于追踪成功检测的次数
        is_pass = False  # 用于保存质检是否成功
        Color_choice = Color_choice #用于判定质检二维码颜色
        cap = cv2.VideoCapture(0) #选择使用的摄像头
        detect_obj = cv2.wechat_qrcode_WeChatQRCode('detect.prototxt', 'detect.caffemodel', 'sr.prototxt',
                                                    'sr.caffemodel') #使用的二维码识别模型
        for _ in range(3):
            manager.update_constant("正在读取图像")

            if cap is not None:
                # 读取一帧图像
                ret, frame = cap.read()
                if ret:
                    # 成功读取到图像
                    cv2.imwrite('frame.bmp', frame)

                    if Color_choice:
                        # 反转图像颜色
                        frame = cv2.bitwise_not(frame, frame)

                    manager.update_constant("正在确定二维码位置")
                    # 使用模型获取图片中二维码的内容和位置
                    res, points = detect_obj.detectAndDecode(frame)
                    # 如果检测到二维码坐标
                    if points:
                        array_data = points[0]
                        # 将NumPy数组转换为Python列表
                        array_data_list = array_data.tolist()
                        line2 = (array_data[1, 1], array_data[1, 0], array_data[2, 1], array_data[2, 0])
                        manager.update_constant("正在计算位置与角度")
                        is_position_correct = self.compare_points(qrPoint, array_data)
                        angle = self.calculate_angle_between_lines(qrLine, line2)
                        angle_offset_str = str(angle)
                    # 如果检测到二维码内容
                    if res:
                        successful_detection_count += 1
                        # 检测到二维码内容后跳出循环
                        break

            else:
                # 无法打开摄像头或读取图像
                print("无法打开摄像头或读取图像")

        #关闭摄像头资源
        cap.release()

        # 如果在三次检测中至少有一次成功检测到二维码
        if successful_detection_count > 0:
            is_pass = True
        else:
            is_pass = False

        return array_data_list, angle_offset_str, res, is_position_correct, is_pass
work = QrCode()

# 质检接口可选择黑白二维码检测，判断是否质检合格返回
@app.route('/process_image/<Color_choice>', methods=['POST'])
def process_image1(Color_choice):
    try:
        array_data_list, angle_offset_str, res, is_position_correct, is_pass = work.QRCode_Detection(Color_choice)
        # 构建响应数据
        response_data = {
            'is_pass': is_pass,
            'is_position_correct': is_position_correct,
            'angle_offset': angle_offset_str + 'degrees',
            'info': res
        }
        return jsonify(response_data)

    except Exception as e:
        return jsonify({'error': str(e)})

# 质检接口，纯数据返回
@app.route('/process_image_data/<Color_choice>', methods=['POST'])
def process_image_data(Color_choice):
        try:
            array_data_list, angle_offset_str, res, is_position_correct, is_pass = work.QRCode_Detection(Color_choice)
            # 构建响应数据
            response_data = {
                'position_correct': array_data_list,
                'angle_offset': angle_offset_str,
                'info': res
            }

            return jsonify(response_data)
        except Exception as e:
            return jsonify({'error': str(e)})

# 获取质检运行状态
@app.route('/state', methods=['GET'])
def state():
    return manager.get_constant()


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
